#include "../inc/mzrtos.h"
#include "../inc/mzhw.h"

//todo-jianglin: Add state of thread

extern mz_thread_t mz_current_thread;
extern struct mz_list_node mz_thread_priority_list[MZ_THREAD_PRIORITY_MAX];

static void _mz_thread_timer_entry(void* arg){
    mz_thread_t thread;
    thread = (mz_thread_t)arg;

    mz_list_insert_before(&mz_thread_priority_list[thread->current_priority], &thread->list);
}

static void _mz_thread_init(mz_thread_t thread,
                            const char* name,
                            void (*entry)(void* arg),
                            void* arg,
                            void* stack_addr,
                            mz_uint32_t stack_size,
                            mz_uint8_t priority,
                            mz_tick_t tick){
    thread->entry = entry;
    thread->arg = arg;

    thread->init_tick = thread->remaining_tick = tick;

    thread->current_priority = thread->init_priority = priority;
    thread->stack_addr = stack_addr;
    thread->stack_size = stack_size;

    mz_object_init(&thread->parent, name, MZ_OBJECT_THREAD);

    mz_timer_init(&thread->timer, name, _mz_thread_timer_entry, thread, 0, MZ_TIMER_ONE_SHOT);

    mz_list_init(&thread->list);
    mz_list_insert_before(&mz_thread_priority_list[thread->current_priority], &thread->list);

    thread->sp = (void*)mz_hw_stack_init((void*)entry,
                                         (void*)arg,
                                         (mz_uint8_t*)((char*)thread->stack_addr + thread->stack_size - 4));
}

void mz_thread_init(mz_thread_t thread,
                    const char* name,
                    void (*entry)(void* arg),
                    void* arg,
                    void* stack_addr,
                    mz_uint32_t stack_size,
                    mz_uint8_t priority,
                    mz_tick_t tick){
    mz_uint32_t level = mz_hw_interrupt_disable();

    _mz_thread_init(thread, name, entry, arg,stack_addr, stack_size, priority, tick);

    mz_hw_interrupt_enable(level);
}

/* This function is used to obtain the handle of the currently running thread */
mz_thread_t mz_thread_self(void){
    return mz_current_thread;
}

void mz_thread_delay(mz_tick_t tick){
    mz_thread_t thread;
	
    mz_uint32_t level = mz_hw_interrupt_disable();

    thread = mz_thread_self();

    thread->timer.cycle = tick;
    thread->timer.repeat = 1;

    mz_list_remove(&thread->list);

    mz_timer_start(&thread->timer);
	
    mz_schedule();

    mz_hw_interrupt_enable(level);
}
void mz_thread_yield(void){
    mz_thread_t thread = mz_current_thread;

    thread->remaining_tick = thread->init_tick;

    mz_list_remove(&thread->list);

    mz_list_insert_before(&mz_thread_priority_list[thread->current_priority], &thread->list);

    mz_schedule();
}
